;
; vmpref.asm
;

include vmbdoor.inc

; enable x486 instructions, but use 16 bit segment
.486
option segment:use16

; code segment
codes	segment para use16 public 'CODE'
codes	ends

; data segment
datas	segment byte use16 public 'DATA'
BDOOR_MAGIC	dword  	VMWARE_MAGIC
BDOOR_PORT  	word	VMWARE_PORT
FEATURE_ON	byte	TAB,'On$'
FEATURE_OFF	byte	TAB,'Off$'
OPTION_INDENT	byte	'   $'
OPTION_G	byte	'G', TAB, 'Grab by cursor move$'
OPTION_U	byte	'U', TAB, 'Ungrab by cursor move$'
OPTION_S	byte	'S', TAB, 'Scroll by cursor move$'
OPTION_C	byte	'C', TAB, 'Copy and Paste  $'
OPTION_T	byte	'T', TAB, 'Time syncronization$'
MSG_USAGE	byte	\
	'Usage: vmpref [[<action>]<feature>]', CR, LF, \
	CR, LF, \
	'<action>', CR, LF, \
	'  +', TAB, 'Enables specified feature.', CR, LF, \
	'  -', TAB, 'Disables specified feature.', CR, LF, \
	'When <action> option is omitted, the default', CR, LF, \
	'action is to "toggle" current setting.', CR, LF, \
	CR, LF, \
	'<feature>$'
MSG_USAGE2	byte	\
	'<feature> options are case insensitive.', CR, LF, \
	'When <feature> option is omitted, preference', CR, LF, \
	'setting is not changed.$'
MSG_VMNG	byte	'Not running inside VMware.$'
END_OF_LINE	byte	CR, LF, '$'
datas	ends

main	group codes,datas

codes	segment
; for tiny memory model (.com), all seg is the same
assume	cs:main,ds:main,es:main,ss:main
org	100h
entry:
check_vm	proc near
	; Check if we are running inside VMware
	mov 	cx, VMCMD_GET_VERSION
        call	backdoor

	cmp	ebx,[BDOOR_MAGIC]
	jne	not_in_vm
check_vm	endp

;************************************************
; Process command line
;************************************************
command_line	proc near
	mov	cl, byte ptr [80h]		; command line length
	mov	si, byte ptr [81h]		; command line top

	xor	bx, bx				; target feature
	xor	dl, dl				; action (default:toggle)

next_char:
	dec	cl				; end of command line?
	jz	get_pref			; yes. do the actual operation

	cld					; clear direction flag so that
						; lodsb will increment SI
	lodsb					; mov al,[ds:si] & inc si

	cmp	al, CR				; CR character?
	je	get_pref			; yes. end of command line

	cmp	al, ' '				; blank?
	je	next_char			; yes. get next char

	cmp	al, TAB				; tab?
	je	next_char			; yes. get next char

	cmp	al, '-'				; minus?
	je	set_disable			; yes. set disconnect flag

	cmp	al, '+'				; plus?
	je	set_enable			; yes. clear disconnect flag

	cmp	al, 'A'				; below 'A' ?
	jb	usage				; yes. invalid option

	cmp	al, 'Z'				; below 'Z' ?
	jbe	select				; yes. select feature

	cmp	al, 'a'				; below 'a' ?
	jb	usage				; yes. invalid option

	cmp	al, 'z'				; below 'z' ?
	ja	usage				; no. invalid option

	sub	al, 20h				; convert to upper case

select:
	cmp	al, 'G'				; Grab option
	je	set_grab

	cmp	al, 'U'				; Ungrab option
	je	set_ungrab

	cmp	al, 'S'				; Scroll option
	je	set_scroll

	cmp	al, 'C'				; Copy & paste option
	je	set_copy_paste

	cmp	al, 'T'				; Time syncronize option
	je	set_syncro

	jmp	usage				; invalid option

set_disable:
	mov	dl, 0ffh			; action = disable
	jmp	next_char			; read next char

set_enable:
	mov	dl, 1				; action = enable
	jmp	next_char			; read next char

set_grab:
	mov	bx, VMPREF_GRAB_MOVE
	jmp	get_pref

set_ungrab:
	mov	bx, VMPREF_UNGRAB_MOVE
	jmp	get_pref

set_scroll:
	mov	bx, VMPREF_SCROLL_MOVE
	jmp	get_pref

set_copy_paste:
	mov	bx, VMPREF_COPY_PASTE
	jmp	get_pref

set_syncro:
	mov	bx, VMPREF_SYNCRONIZE
	;jmp	get_pref
command_line	endp

;************************************************
; get current preferenct settings
;************************************************
get_pref	proc near
	push	bx				; store option mask
	push	dx				; store action flag

	mov	cx, VMCMD_GET_SETTING		; get current settings
	call	backdoor

	pop	dx				; restore action flag
	pop	bx				; restore option mask

	and	bx, bx				; check specified option
	jz	list_pref			; if none, only show list
	jmp	change_pref			; otherwise, change setting
get_pref	endp

;************************************************
; terminate routines
;************************************************
not_in_vm:
	mov	dx, offset MSG_VMNG		; not in VM message
	call	print_msg
	xor	al, al				; return code = 0

terminate:					; Now Return to DOS
	mov	ah, 4ch
	int	21h
	; this function call never returnes

;************************************************
; usage help
;************************************************
usage	proc	near
	mov	dx, offset MSG_USAGE		; usage message
	call	print_msg
	call	line_feed

	mov	dx, offset OPTION_G
	call	print_opt
	call	line_feed

	mov	dx, offset OPTION_U
	call	print_opt
	call	line_feed

	mov	dx, offset OPTION_S
	call	print_opt
	call	line_feed

	mov	dx, offset OPTION_C
	call	print_opt
	call	line_feed

	mov	dx, offset OPTION_T
	call	print_opt
	call	line_feed

	mov	dx, offset MSG_USAGE2
	call	print_msg
	call	line_feed

	jmp	terminate
usage	endp

;************************************************
; change preference settings
;************************************************
change_pref	proc near
	and	dl, dl				; check action flag
	js	disable				; if minus, disable
	jnz	enable				; if not zero, enable

	; bx = specified option
	; ax = current settings
toggle:
	mov	cx, bx
	and	cx, ax
	jnz	disable				; currently enabled

enable:
	or	bx, ax
	jmp	set_pref

disable:
	not	bx
	and	bx, ax

set_pref:
	mov	cx, VMCMD_SET_SETTING		; change settings
	call	backdoor

	mov	cx, VMCMD_GET_SETTING		; get latest settings
	call	backdoor
	; now print changed setting list
change_pref	endp

;************************************************
; List current preferrence settings
;************************************************
list_pref	proc near
	; Grab feature
	mov	dx, offset OPTION_G
	call	print_opt
	mov	cx, VMPREF_GRAB_MOVE
	call	print_stat

	; Ungrab feature
	mov	dx, offset OPTION_U
	call	print_opt
	mov	cx, VMPREF_UNGRAB_MOVE
	call	print_stat

	; Scroll feature
	mov	dx, offset OPTION_S
	call	print_opt
	mov	cx, VMPREF_SCROLL_MOVE
	call	print_stat

	; Copy & paste feature
	mov	dx, offset OPTION_C
	call	print_opt
	mov	cx, VMPREF_COPY_PASTE
	call	print_stat

	; Time syncronize feature
	mov	dx, offset OPTION_T
	call	print_opt
	mov	cx, VMPREF_SYNCRONIZE
	call	print_stat

	jmp	terminate
list_pref	endp

;************************************************
; executes vmware backdoor i/o
;************************************************
backdoor	proc near
        mov	eax, [BDOOR_MAGIC]
        mov	dx, [BDOOR_PORT]
        in	eax, dx
	ret
backdoor	endp

;************************************************
; print option string
;************************************************
; dx= option name address
; ax must be preserved
print_opt	proc near
	push	ax
	push	dx

	mov	dx, offset OPTION_INDENT
	call	print_msg

	pop	dx
	call	print_msg

	pop	ax
	ret
print_opt	endp

;************************************************
; print status string
;************************************************
; ax=current settings
; cx=setting mask to print status
; ax must be preserved
print_stat	proc near
	push	ax
	mov	dx, offset FEATURE_ON

	and	ax, cx
	jnz	enabled
	add	dx, 4				; FEATURE_OFF string
enabled:
	call	print_msg
	call	line_feed

	pop	ax
	ret
print_stat	endp

;************************************************
; output line feed
;************************************************
line_feed	proc near
	mov	dx, offset END_OF_LINE
	call	print_msg
	ret
line_feed	endp

;************************************************
; call DOS print function
;************************************************
print_msg	proc near
	mov 	ah, 09h				; print function 
	int	21h				; DOS function call
	ret
print_msg	endp

codes	ends
end	entry
; end of file
